/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2020.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* Listing 22-7 */

/* signalfd_sigval.c

   Usage: signalfd_sigval sig-num...

   Demonstrate the use of signalfd() to receive signals via a file descriptor.

   This program is Linux-specific. The signalfd API is supported since kernel
   2.6.22.
*/
#include <sys/signalfd.h> // for struct signalfd_siginfo
#include <signal.h>
#include "tlpi_hdr.h"

int
main(int argc, char *argv[])
{
	sigset_t mask = {};
	int sfd = 0, j = 0;
	struct signalfd_siginfo fdsi = {};
	ssize_t s = 0;

	if (argc < 2 || strcmp(argv[1], "--help") == 0)
		usageErr("%s sig-num...\n", argv[0]);

	printf("%s: PID = %ld\n", argv[0], (long) getpid());

	sigemptyset(&mask);
	for (j = 1; j < argc; j++)
		sigaddset(&mask, atoi(argv[j]));

	if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
		errExit("sigprocmask");

	sfd = signalfd(-1, &mask, 0);
	if (sfd == -1)
		errExit("signalfd");

	for (;;) {
		s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
		
		if (s != sizeof(struct signalfd_siginfo))
			errExit("read");

		printf("%s: got signal %d", argv[0], fdsi.ssi_signo);
		if (fdsi.ssi_code == SI_QUEUE) {
			printf("; ssi_pid = %d; ", fdsi.ssi_pid);
			printf("ssi_int = %d", fdsi.ssi_int);
		}
		printf("\n");
	}
}
